/* Copyright (c) 2010, Michael J. Allison

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, 
 this list of conditions and the following disclaimer.
 
 * Redistributions in binary form must reproduce the above copyright notice, 
 this list of conditions and the following disclaimer in the documentation 
 and/or other materials provided with the distribution.
 
 * Neither the name of Michael J. Allison nor the names of contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 THE POSSIBILITY OF SUCH DAMAGE.
 */

package xamcommons.objectinspector;

import java.util.Vector;

import javax.swing.table.AbstractTableModel;

import org.snia.xam.FieldContainer;
import org.snia.xam.XAMException;
import org.snia.xam.XAMLibrary;
import org.snia.xam.XIterator;
import org.snia.xam.util.ISO8601Date;

/**
 * Builds a table model of a FieldContainer. May be extended in the future 
 * to refresh the field container in a polled fashion. This class may not 
 * scale to large field containers.
 */
public class FieldContainerDataModel
   extends AbstractTableModel
{
   private static final String COL_LABEL_NAME   = "Name";
   private static final String COL_LABEL_TYPE   = "Type";
   private static final String COL_LABEL_RO     = "RO";
   private static final String COL_LABEL_BIND   = "Binding";
   private static final String COL_LABEL_LENGTH = "Length";
   private static final String COL_LABEL_VALUE  = "Value";
   private static final String COL_LABEL_STATUS = "Status";
   
   private final int COL_COUNT = 7;
   private final int COL_STATUS = 0;
   private final int COL_NAME   = 1;
   private final int COL_TYPE   = 2;
   private final int COL_RO     = 3;
   private final int COL_BIND   = 4;
   private final int COL_LENGTH = 5;
   private final int COL_VALUE  = 6;
   
   private Vector<Object[]> m_data = new Vector<Object[]>();
   private FieldContainer   m_fc;
   private String           m_className;
   
   /** 
    * Get each field from the FieldContainer and cache a copy of the field
    * information. 
    */
   FieldContainerDataModel( String className, FieldContainer fc )
      throws XAMException
   {
      m_className = className;
      CanonicalClass fieldClass = CanonicalClass.GetClass(className);
      m_fc = fc;
      
      XIterator iter = fc.openFieldIterator("");
      while(iter.hasNext())
      {
         Object[] row = new Object[COL_COUNT];
         String  fieldName = iter.next();
         String  fieldType = fc.getFieldType( fieldName );
         boolean readOnly  = fc.getFieldReadOnly( fieldName );
         boolean binding   = fc.getFieldBinding( fieldName );
         
         row[COL_STATUS] = fieldClass.checkField( fieldName, readOnly, binding, fieldType );
         row[COL_NAME]   = fieldName;
         row[COL_TYPE]   = translateType(fieldType);
         row[COL_RO]     = (readOnly?"ro":"");
         row[COL_BIND]   = (binding?"bound":"");
         row[COL_LENGTH] = String.valueOf(fc.getFieldLength( fieldName ));
         
         if( fieldType.equals(XAMLibrary.STYPE_STRING_MIME_TYPE))
            row[COL_VALUE] = fc.getString( fieldName );
         else if( fieldType.equals(XAMLibrary.STYPE_INT_MIME_TYPE))
            row[COL_VALUE] = String.valueOf(fc.getLong( fieldName ));
         else if( fieldType.equals(XAMLibrary.STYPE_DOUBLE_MIME_TYPE))
            row[COL_VALUE] = String.valueOf(fc.getDouble( fieldName ));
         else if( fieldType.equals(XAMLibrary.STYPE_BOOLEAN_MIME_TYPE))
            row[COL_VALUE] = String.valueOf(fc.getBoolean( fieldName ));
         else if( fieldType.equals(XAMLibrary.STYPE_DATETIME_MIME_TYPE))
            row[COL_VALUE] = ISO8601Date.toISO8601String(fc.getDateTime( fieldName ));
         else if( fieldType.equals(XAMLibrary.STYPE_XUID_MIME_TYPE))
            row[COL_VALUE] = fc.getXUID( fieldName ).toString();
         
         m_data.add(row);
      }
   }
   
   /**
    * Returns a human readable version of the MIME type IFF it is one of the 
    * XAM type. Will return the parameter otherwise. 
    * @param fieldType
    * @return The MIME type, or the shortcut for XAM predefined types. 
    */
   private String translateType(String fieldType)
   {
      if( fieldType.equals( XAMLibrary.STYPE_BOOLEAN_MIME_TYPE ))
         return "xam_boolean";
      
      else if( fieldType.equals( XAMLibrary.STYPE_DATETIME_MIME_TYPE ))
         return "xam_datetime";
      
      else if( fieldType.equals( XAMLibrary.STYPE_DOUBLE_MIME_TYPE ))
         return "xam_double";
      
      else if( fieldType.equals( XAMLibrary.STYPE_INT_MIME_TYPE ))
         return "xam_int";
      
      else if( fieldType.equals( XAMLibrary.STYPE_STRING_MIME_TYPE ))
         return "xam_string";
      
      else if( fieldType.equals( XAMLibrary.STYPE_XUID_MIME_TYPE ))
         return "xam_xuid";
      
      else
         return fieldType;
   }
   
   /**
    * Hard coded, since the field attributes are always the same:
    *    Name
    *    Type
    *    ReadOnly
    *    Binding
    *    Length
    *    Value
    */
   public int getColumnCount()
   {
      return COL_COUNT;
   }
   
   public int getRowCount()
   {
      return m_data.size();
   }
   
   public Object getValueAt(int rowIndex, int columnIndex)
   {
      Object[] row = null;
      row = m_data.get(rowIndex);
      return row[columnIndex];
   }
   
   public String getColumnName( int index )
   {
      switch( index ) 
      {
      case COL_STATUS:
         return COL_LABEL_STATUS;
      case COL_NAME:
         return COL_LABEL_NAME;
      case COL_TYPE:
         return COL_LABEL_TYPE;
      case COL_RO:
         return COL_LABEL_RO;
      case COL_BIND:
         return COL_LABEL_BIND;
      case COL_LENGTH:
         return COL_LABEL_LENGTH;
      case COL_VALUE:
         return COL_LABEL_VALUE;
      default:
         return "?";
      }
   }
}
